NOMOR 3: Analisis Klasifikasi Komprehensif¶
Narasi¶
PDM Paylater adalah perusahaan fiktif penyedia layanan Buy Now Pay Later (BNPL) yang utamanya mendapatkan pendapatan dengan memberikan pinjaman uang. Salah satu risiko utama dalam praktik ini adalah kemungkinan peminjam gagal membayar pinjamannya, dengan menghentikan pembayaran sesuai kesepakatan. Hal ini akan menyebabkan kerugian keuangan bagi perusahaan.
Untuk mengurangi kerugian tersebut, sangat penting bagi PDM Paylater untuk membuat keputusan yang terinformasi (berbasiskan data) tentang kepada siapa memberikan pinjaman. Pada dasarnya, mereka perlu menilai risiko yang terkait dengan setiap peminjam dan membuat keputusan pemberian pinjaman berdasarkan hal itu.
Tugas Anda adalah membantu PDM Paylater dalam mengatasi tantangan ini. Anda akan melakukannya dengan mengevaluasi kemampuan setiap calon peminjam untuk melakukan pembayaran yang akan memungkinkan pengambilan keputusan pemberian pinjaman yang terinformasi dengan baik. Model ini akan membantu menentukan calon peminjam mana yang layak mendapatkan pinjaman.
Dataset¶
Dataset yang digunakan dapat diakses melalui link berikut: Dataset Nomor 3
- variabel_description.csv: metadata
- train.csv: Dataset utama yang digunakan dalam pembentukan model klasifikasi, berisi informasi setiap aktivitas pengajuan pinjaman (aplikasi) oleh seorang calon peminjaman. Label target yang digunakan adalah
FLAG, menunjukan apakah seorang calon peminjam akan diberikan pinjaman (1) atau tidak (0). Hal ini didasarkan pada prediksi apakah seorang calon peminjam akan sanggup dalam memenuhi kewajibannya melunasi pinjaman dengan tepat waktu atau tidak. - test.csv: Digunakan dalam uji performa (evaluasi) model terbaik yang dibentuk menggunakan dataset train.csv. Berisi informasi setiap aktivitas pengajuan pinjaman oleh seorang calon peminjam. Label target yang digunakan adalah
FLAG. - previous_application.csv: Berisi informasi tentang data pengajuan pinjaman (aplikasi) sebelumnya. Terhubung dengan data train.csv dan test.csv berdasarkan fitur
U_ID. - payment_history.csv: Data pembayaran yang lalu untuk setiap pinjaman sebelumnya. Terhubung dengan data train.csv dan test.csv berdasarkan fitur
U_ID, serta terhubung dengan data previous_application.csv berdasarkan fiturSK_ID_PREV.
Tugas¶
Peserta dibebaskan menggunakan semua dataset, dengan 2 dataset utama yang wajib digunakan adalah train.csv (untuk pemodelan) dan test.csv (untuk evaluasi).
- Jelaskan langkah-langkah pra-pemrosesan data (Preprocessing) yang Anda lakukan secara detail dan sejelas mungkin.
- Pada Notebook ini tahapan preprocessing terbagi menjadi 3 bagian
- Bagian 1: Dilakukan data cleaning dengan tujuan memperbaiki atau menghapus kesalahan, ketidakkonsistenan, dan ketidakakuratan dalam kumpulan data. Identifikasi hal ini cukup dilakukan pada dataset train.csv dan test.csv (karena yang wajib digunakan dalam analisis) serta dilakukan secara general berdasarkan eksplorasi awal.
- Bagian 2: Pada bagian ini dilakukan pra-pemrosesan data dan feature engineering melanjutkan proses data cleaning sebelumnya untuk digunakan dalam proses pemodelan berdasarkan insight yang diperoleh pada bagian EDA.
- Bagian 3: Beberapa tahapan preprocessing data menggunakan operator
pipelinepada scikit-learn agar lebih mudah digunakan dan menghindari kemungkinan terjadinya kebocoran (leakage) data tes saat pemodelan.
- Peserta diwajibkan membuat setidaknya 3 fitur baru, dengan mengekstrak nilai fitur dari dataset train.csv, test.csv, previous_application.csv dan payment_history.csv. Transformasi data dengan mengubah satuan (seperti hari menjadi tahun) tidak dihitung sebagai pembentukan fitur baru. Dataset utama dalam analisis ini adalah train.csv dan test.csv sehingga hasil fitur baru digabungkan dengan setiap dataset ini (tidak boleh salah satu).
- Peserta diwajibkan menggunakan setidaknya 3 metode preprocessing data berbeda pada tahapan preprocessing bagian 3 (
pipeline). Jika dilakukan imputasi missing value menggunakan modus untuk data kategorik dan mean untuk data numerik akan dihitung sebagai 1 metode preprocessing yang sama.
- Lakukanlah tahapan Exploratory Data Analysis (EDA) untuk mendapatkan insight yang bermanfaat dari data. Pada tahapan ini anda harus membuat setidaknya 5 pertanyaan yang akan dijawab berdasarkan hasil eksplorasi dan visualisasi serta wajib menjawab 3 pertanyaan berikut:
- Bagaimana sebaran proporsi pada label target (
FLAG)? - Bagaimana pola jumlah pinjaman yang disetujui (
APPROVED_CREDIT) dan karakteristiknya berdasarkan jenis kontrak (CONTRACT_TYPE)? - Terdapat korelasi yang kuat antara 3 fitur, yaitu
Product Price,Loan AnnuitydanApproved Credit(tunjukan dengan heatmap correlation). Dalam hal ini, pemodelan klasifikasi nantinya hanya akan menggunakan fiturProduct Price. Kenapa demikian? (Hint: pertimbangkan ketersediaan data pada saat calon peminjam baru mengajukan pinjaman) - Tambahkan 5 pertanyaan lainnya dan jawab berdasarkan hasil eksplorasi dan visualisasi data.
- Pilihlah metrik evaluasi yang Anda gunakan untuk menilai performa model (tahapan pemodelan serta pemilihan model terbaik) dan berikan penjelasan menyeluruh tentang alasan Anda memilih metrik tersebut. Pada bagian evaluasi akhir (uji performa menggunakan data test.csv) anda wajib menginterpretasikan setidaknya menggunakan 3 metrik evaluasi yang berbeda.
- Pilihlah model terbaik dengan membandingkan beberapa model klasifikasi (minimal 7 model yang berbeda) dan berikan penjelasan mengapa model tersebut dipilih sebagai yang terbaik.
- Lakukanlah uji performa pada data test.csv dengan menggunakan setidaknya 3 metrik evaluasi yang berbeda dan berikan interpretasi.
- Berikan penjelasan tentang fitur-fitur yang paling penting pada model terbaik yang dipilih dan jelaskan bagaimana dan mengapa fitur-fitur tersebut sangat penting.
- Berikan juga rekomendasi & kesimpulan menyeluruh terhadap bisnis PDM Paylater berdasarkan hasil analisis yang telah dilakukan.
Hint¶
- Contoh pembuatan fitur baru: Dibentuk fitur
PRE_LATE- Nilainya berupa 1: Pernah telat bayar, 0: Tidak pernah telat bayar
- Diperoleh dari dataset payment_history dengan membandingkan fitur nilai pada
Ints days(waktu jatuh jempo) danPays Days(waktu dibayar sebenarnya) yang kemudian di aggregate jumlahnya berdasarkan fiturU_ID, sehingga diperoleh insight apakah seorang calon peminjam pernah telat dalam membayar pada peminjaman sebelumnya (jumlah telat > 1 diubah nilainya menjadi 1) - Hasilnya digabungkan ke dataset train dan test berdasarkan fitur
U_IDdengan metode penggabungan yang mempertahankan seluruh baris observasi pada kedua dataset ini (train dan test). - Jika terdapat nilai NA pada fitur
PRE_LATE(yang telah digabungkan ke data train dan test), maka diimputasi dengan nilai 0. Artinya belum ada riwayat peminjaman sebelumnya oleh calon peminjam tersebut.
- Referensi operator pipeline pada scikit learn
- Referensi Feature Importance
- Referensi SHAP values
- Referensi SHAP values individual/SHAP Force Plot
Perhatikan!!!¶
Tahapan pemodelan dan EDA hanya menggunakan data train.csv. Tahapan evaluasi akhir menggunakan data test.csv. Dataset lainnya digunakan dalam feature engineering dengan membuat fitur baru pada dataset train.csv dan test.csv (wajib keduanya).
Hati-hati pada saat penggabungan fitur baru dengan dataset train.csv dan test.csv
Peserta diizinkan melewatkan operator pipeline pada preprocessing bagian 3, tetapi akan mendapatkan pengurangan nilai.
Gunakan alur seperti yang ditunjukan pada Outline dibawah untuk mempermudah analisis, detailnya dapat disesuaikan dengan preferensi masing-masing.
Peserta dilarang melakukan optimalisasi model menggunakan metode hyperparameter tunning dan sejenisnya. Oleh karena itu, peserta dilarang mengatur parameter setiap model selain random_state dan verbose. Contoh yang benar:
- RidgeClassifier(random_state=0)
- RandomForestClassifier(random_state=0)
- CatBoostClassifier(random_state=0, verbose=0)
Dilarang seperti berikut: - XGBClassifier(random_state=0, n_estimators = 500, learning_rate= 0.01, max_depth = 5)
Hasil splitting pada data train.csv akan disebut sebagai data train dan data validasi. Peserta bebas dalam pengaturan proporsi dan penggunaan random_state pada splitting data. Data latih (train) sekurang-kurangnya 60% dari train.csv
Peserta diizinkan untuk dengan/tidak menggunakan berbagai metode penanganan data tidak seimbang dengan memperhatikan data leakage.
Peserta dilarang menambah dan/atau menghapus observasi (baris) pada dataset test.csv
Untuk mempermudah interpretasi pada tahapan Post Analysis, peserta diharapkan tidak menggunakan metode encoding dengan One Hot Encoding atau dummy. Disarankan menggunakan metode Label Encoder atau Ordinal Encoder.
Bagian Post Analysis cukup dilakukan dengan menjalankan syntax yang disediakan dan memberikan interpretasi output (Feature Importance)
Bonus Point¶
- Peserta membuat metrik evaluasi sendiri secara logis menggunakan fungsi
make_scorerpada scikit learn - Membuat fungsi perulangan yang menggabungkan operator
pipelinedan kandidat model serta menghasilkan output performa masing-masing model. - Terdapat fitur baru yang dibentuk yang masuk kedalam 5 fitur terbaik pada plot Feature Importance
- Melanjutkan tahapan Post Analysis menggunakan konsep SHAP values untuk mengetahui bagaimana pola pengaruh fitur terhadap label target (
FLAG) dan SHAP Force Plot / SHAP values individual** dengan 2 sampel (individu) data pengajuan pinjaman.
Outline¶
# Impor library yang akan digunakan
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly
import plotly.graph_objects as go
import plotly.offline as pyo
from plotly.offline import iplot
import warnings
warnings.filterwarnings("ignore")
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, classification_report, roc_auc_score, roc_curve
from sklearn.preprocessing import OrdinalEncoder
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
# Mengatur tampilan untuk seaborn
sns.set(context= "notebook", color_codes=True)
plt.style.use('bmh')
pyo.init_notebook_mode()
%matplotlib inline
Metadata¶
## Jika menggunakan google colab dan dataset pada google drive, jalankan 2 baris syntax berikut
# from google.colab import drive
# drive.mount('/content/drive')
# Impor data variabel description
df_var = pd.read_csv('/Users/revaldyhazzadaniswara/Downloads/variable_description.csv')
pd.set_option('display.max_colwidth', None)
display(df_var)
# Mengetahui jumlah dan tipe data variable description
df_var.info()
Dataset¶
# Impor data yang akan digunakan
df_tr = pd.read_csv('/Users/revaldyhazzadaniswara/Downloads/train.csv')
df_te = pd.read_csv('/Users/revaldyhazzadaniswara/Downloads/test.csv')
df_pre = pd.read_csv('/Users/revaldyhazzadaniswara/Downloads/previous_applications.csv')
df_his = pd.read_csv('/Users/revaldyhazzadaniswara/Downloads/payment_history.csv')
# Menampilkan data train dan data test
display(df_tr.head(), df_te.head())
# Menampilkan data previous application dan payment history
display(df_pre.head(), df_his.head())
# Deskriptif Statistik untuk tiap data yang digunakan
display(df_tr.describe(), df_te.describe(), df_pre.describe(), df_his.describe())
# Menampilkan informasi dasar data yang akan digunakan
display(df_tr.info(), df_te.info(), df_his.info(), df_pre.info())
1 - Preprocessing Data (1)¶
Dilakukan data cleaning dengan tujuan memperbaiki atau menghapus kesalahan, ketidakkonsistenan, dan ketidakakuratan dalam kumpulan data. Identifikasi hal ini cukup dilakukan pada dataset train.csv dan test.csv (karena yang wajib digunakan dalam analisis) serta dilakukan secara general berdasarkan eksplorasi awal. Jelaskan setiap bagian preprocessing yang dilakukan!
# Melihat missing values dari setiap data yang akan digunakan
display(df_tr.isnull().sum())
display(df_te.isnull().sum())
display(df_pre.isnull().sum())
display(df_his.isnull().sum())
Imputation¶
Mengisi nilai numerik (LOAN_ANNUITY dan PRODUCT_PRICE) yang kosong dengan median
# Mengisi nilai LOAN_ANNUITY dan PRODUCT_PRICE
fillannuitytr = df_tr['LOAN_ANNUITY'].median()
fillpricetr = df_tr['PRODUCT_PRICE'].median()
fillannuityte = df_te['LOAN_ANNUITY'].median()
fillpricete = df_te['PRODUCT_PRICE'].median()
df_tr['LOAN_ANNUITY'].fillna(fillannuitytr, inplace = True)
df_tr['PRODUCT_PRICE'].fillna(fillpricetr, inplace = True)
df_te['LOAN_ANNUITY'].fillna(fillannuityte, inplace = True)
df_te['PRODUCT_PRICE'].fillna(fillpricete, inplace = True)
display(df_tr.isna().sum(), df_te.isna().sum())
Mengisi nilai external score 1,2, dan 3 dengan 0. Hal ini didasarkan pada keterbatasan data eksternal. Sehingga untuk analisis yang lebih konservatif serta meminimalisasi risiko untuk pemberian pinjaman, diisi nilai 0.
# Mengisi nilai external score 1,2, dan 3 dengan nilai 0
df_tr['EXTERNAL_SCORE_1'].fillna(0, inplace=True)
df_tr['EXTERNAL_SCORE_2'].fillna(0, inplace=True)
df_tr['EXTERNAL_SCORE_3'].fillna(0, inplace=True)
df_te['EXTERNAL_SCORE_1'].fillna(0, inplace=True)
df_te['EXTERNAL_SCORE_2'].fillna(0, inplace=True)
df_te['EXTERNAL_SCORE_3'].fillna(0, inplace=True)
# Melihat data kosong setelah dilakukan imputasi
display(df_tr.isna().sum(), df_te.isna().sum())
# Melihat Distribusi Kategori Organisasi untuk Kategori Pendapatan Pensioner
pensioner_data = df_tr[df_tr['INCOME_CATEGORY'] == 'Pensioner']
pension_organization_counts = pensioner_data['ORGANIZATION_CATEGORY'].value_counts()
print("Distribusi Kategori Organisasi untuk Kategori Pendapatan Pensioner:")
print(pension_organization_counts)
# Mengganti 'NA1' with 'No Organizational Contract' pada df_tr dan df_te
df_tr.loc[df_tr['INCOME_CATEGORY'] == 'Pensioner', 'ORGANIZATION_CATEGORY'] = df_tr.loc[df_tr['INCOME_CATEGORY'] == 'Pensioner', 'ORGANIZATION_CATEGORY'].replace('NA1', 'No Organizational Contract')
df_te.loc[df_te['INCOME_CATEGORY'] == 'Pensioner', 'ORGANIZATION_CATEGORY'] = df_te.loc[df_te['INCOME_CATEGORY'] == 'Pensioner', 'ORGANIZATION_CATEGORY'].replace('NA1', 'No Organizational Contract')
2 - Exploratory Data Analysis (EDA)¶
Tahapan ini dilakukan untuk mendapatkan insight yang bermanfaat dari data. Pada tahapan ini anda harus membuat setidaknya 5 pertanyaan tambahan yang akan dijawab berdasarkan hasil eksplorasi dan visualisasi selain 3 pertanyaan wajib
2.1 - Bagaimana sebaran proporsi pada label target (FLAG)?¶
# Membuat plot sebaran flag
sns.countplot(x=df_tr['FLAG'], data=df_tr, palette="tab10")
plt.title("Distribution of The Flag")
plt.show()
# Melihat nilai pada setiap flag
df_tr["FLAG"].value_counts()
Dapat dilihat dari plot dan perbandingan jumlah untuk 0(membayar tepat waktu) dan 1(tidak membayar) sangat berbeda jauh. Hal ini bisa dijadikan pertimbangan nantinya untuk handle imbalanced data untuk meningkatkan F1 Score dari model
JAWAB:
2.2 - Bagaimana pola jumlah pinjaman yang disetujui (APPROVED_CREDIT) dan karakteristiknya berdasarkan jenis kontrak (CONTRACT_TYPE)?¶
Akan dianalisis pola approved credit berdasarkan rata-rata approved credit berdasarkan contract type nya. Sebelum itu, dilakukan outlier analysis terlebih dahulu menggunakan boxplot
# Membuat boxplot dan melihat apakah ada outlier
plt.figure(figsize=(8, 6))
sns.boxplot(data=df_tr, x='CONTRACT_TYPE', y='APPROVED_CREDIT', palette='Set2')
plt.title('Boxplot APPROVED_CREDIT berdasarkan CONTRACT_TYPE')
plt.xlabel('CONTRACT_TYPE')
plt.ylabel('APPROVED_CREDIT')
plt.grid(True)
plt.show()
Membuat data train copy yang untuk melihat mean yang sebenarnya setelah diganti nilai outlier dengan winsorize
from scipy.stats.mstats import winsorize
# Melakukan Winsorizing untuk menggantikan outlier
df_winsorized = df_tr.copy()
df_winsorized['APPROVED_CREDIT'] = winsorize(df_winsorized['APPROVED_CREDIT'], limits=[0.05, 0.05])
# Membuat boxplot setelah Winsorizing
plt.figure(figsize=(8, 6))
sns.boxplot(data=df_winsorized, x='CONTRACT_TYPE', y='APPROVED_CREDIT', palette='Set2')
plt.title('Boxplot APPROVED_CREDIT berdasarkan CONTRACT_TYPE (Winsorized)')
plt.xlabel('CONTRACT_TYPE')
plt.ylabel('APPROVED_CREDIT')
plt.grid(True)
plt.show()
Terlihat outlier berkurang dan akan dilihat distribution plot yang sudah tertanam deskriptif statistik nya
import seaborn as sns
import matplotlib.pyplot as plt
# Fungsi untuk menggambar garis-garis vertikal pada setiap subplot menggunakan deskriptif statistik winsorized
df_summarywin = df_winsorized.describe()
def draw_axvlines(plot, col):
mean = df_summarywin.loc["mean", col]
q1 = df_summarywin.loc["25%", col]
q2 = df_summarywin.loc["50%", col]
q3 = df_summarywin.loc["75%", col]
plot.axvline(mean, color="black", linestyle='dashed', label="Mean")
plot.axvline(q1, color="red", linestyle='dashed', label="25%")
plot.axvline(q2, color="blue", linestyle='dashed', label="50%")
plot.axvline(q3, color="purple", linestyle='dashed', label="75%")
plot.legend()
# Membuat distribusi plot berdasarkan tipe pinjaman pada data train
g = sns.FacetGrid(df_tr, col="CONTRACT_TYPE", col_wrap=4, height=4)
g.map(sns.distplot, "APPROVED_CREDIT", bins=10, color="teal")
# Menambahkan garis-garis vertikal pada setiap subplot
for ax, col in zip(g.axes.flat, df_tr["CONTRACT_TYPE"].unique()):
draw_axvlines(ax, "APPROVED_CREDIT")
# Menampilkan plot
plt.show()
Hal ini bertujuan untuk menggunakan mean setelah dilakukan outlier analysis. Seperti yang kita ketahui, mean sangat berpengaruh terhadap adanya outlier. Ketika outlier sangat jauh, maka mean akan berubah drastis. Oleh karena itu, kita sebenarnya ingin mencari mean sesungguhnya dan meletakkannya di dalam plot
# Melihat rata-rata sesungguhnya dari APPROVED CREDIT berdasarkan CONTRACT_TYPE setelah dilakukan outlier analysis.
df_winsorized.groupby("CONTRACT_TYPE")["APPROVED_CREDIT"].mean().reset_index()
# Melihat proporsi rata-rata APPROVED_CREDIT berdasarkan CONTRACT_TYPE
plt.figure(figsize=(8, 6))
sns.barplot(x="CONTRACT_TYPE", y="APPROVED_CREDIT", data=df_tr.groupby("CONTRACT_TYPE")["APPROVED_CREDIT"].mean().reset_index(), palette="viridis")
plt.xlabel("CONTRACT_TYPE")
plt.ylabel("Rata-rata APPROVED_CREDIT")
plt.title("Rata-rata APPROVED_CREDIT berdasarkan CONTRACT_TYPE")
plt.show()
JAWAB:
Dapat terlihat rata-rata kredit yang diapproved berdasarkan EDA yang sudah dilakukan. Terlihat juga jika semakin tinggi rata-rata nya pada jenis contract type, maka bisa disimpulkan kemungkinan semakin tinggi juga approved credit yang akan diberikan kepada pelanggan.
2.3 - Bagaimana korelasi antar fitur? Fitur apa yang berkorelasi kuat serta bagaimana tindakannya? (merujuk pada penjelasan TUGAS)¶
# Melihat kolom mana saja yang termasuk ke dalam numerik
numeric_columns = df_tr.select_dtypes(include=['int64', 'float64'])
# Menampilkan kolom numerik dan juga korelasi antar atribut numerik nya
display(numeric_columns, numeric_columns.corr())
# Pisahkan Dataframe
databaru = {
'Product Price': df_tr['PRODUCT_PRICE'],
'Loan Annuity': df_tr['LOAN_ANNUITY'],
'Approved Credit': df_tr['APPROVED_CREDIT']
}
df = pd.DataFrame(databaru)
# Buat Matriks korelasinya
correlation_matrix = df.corr()
# Plot Heatmapnya
plt.figure(figsize=(8, 6))
sns.heatmap(correlation_matrix, annot=True, cmap='Oranges', fmt='.2f')
plt.title('Heatmap Correlation antara Product Price, Loan Annuity, dan Approved Credit')
plt.show()
# Membuat plot yang menunjukkan korelasi untuk APPROVED_CREDIT dan PRODUCT_PRICE
sns.regplot(x="APPROVED_CREDIT", y="PRODUCT_PRICE", data=df_tr)
plt.ylim(0,)
plt.show()
print(df_tr[["APPROVED_CREDIT", "PRODUCT_PRICE"]].corr())
# Membuat plot yang menunjukkan korelasi untuk LOAN_ANNUITY dan PRODUCT_PRICE
sns.regplot(x="LOAN_ANNUITY", y="PRODUCT_PRICE", data=df_tr)
plt.ylim(0,)
plt.show()
print(df_tr[["LOAN_ANNUITY", "PRODUCT_PRICE"]].corr())
# Membuat plot yang menunjukkan korelasi untuk LOAN_ANNUITY dan PRODUCT_PRICE
sns.regplot(x="LOAN_ANNUITY", y="APPROVED_CREDIT", data=df_tr)
plt.ylim(0,)
plt.show()
print(df_tr[["LOAN_ANNUITY", "APPROVED_CREDIT"]].corr())
JAWAB:
Terdapat korelasi yang kuat antara 3 fitur, yaitu Product Price, Loan Annuity dan Approved Credit. Dalam hal ini, pemodelan klasifikasi nantinya hanya akan menggunakan fitur Product Price. Karena Product Price memiliki korelasi yang tinggi terhadap dua atribut lain yaitu Loan Annuity dan Approved Credit. Didapat nilai korelasi antara product price dengan approved credit yaitu 0.986786. Sedangkan, nilai korelasi antara product price dan loan annuity sebesar 0.776039. Dengan tingginya nilai korelasi ini diharapkan Product price menjadi sebuah atribut yang nantinya akan representatif terhadap baik itu Loan Annuity maupun Approved Credit. Selain itu dengan tingginya korelasi, memilih satu atribut saja yaitu Product Price bisa mengurangi redundansi atau data yang duplikat.
Untuk alasan teknis, Product Price bisa digunakan sebagai pintu awal pemberian pinjaman. Ketika sebuah perusahaan tahu orang ingin membeli produk apa, maka sebuah perusahaan bisa memperkirakan anuitas selanjutnya dan kredit yang diberikan ke konsumen tentunya. Selain itu, kita juga jadi bisa tahu alasan kekosongan nilai loan annuity dan approved credit. Hal ini bisa saja terjadi karena tidak diapproved credit nya karena tidak tahu ingin membeli produk apa, sehingga tidak dapat anuitas dan approved_credit.
2.4 - Bagaimanakah Distribusi Usia Peminjam yang membayar tepat waktu dan tidak tepat waktu¶
plt.figure(figsize=(10, 8))
df1 = df_tr.copy()
df1['DAYS_AGE'] = abs(df1.copy()['DAYS_AGE'])
# KDE plot of loans that were repaid on time
sns.kdeplot(df1.loc[df_tr.copy()['FLAG'] == 0, 'DAYS_AGE'] / 365, label='flag = 0')
# KDE plot of loans which were not repaid on time
sns.kdeplot(df1.loc[df_tr.copy()['FLAG'] == 1, 'DAYS_AGE'] / 365, label='flag = 1')
# Labeling of plot
plt.style.use('ggplot')
plt.xlabel('Age (years)')
plt.ylabel('Density')
plt.title('Distribution of Ages')
# Display legend
plt.legend()
# Show plot
plt.show()
# Filter dataframe untuk setiap FLAG
ages_flag_0 = df_tr.loc[df_tr['FLAG'] == 0, 'DAYS_AGE'] / 365
ages_flag_1 = df_tr.loc[df_tr['FLAG'] == 1, 'DAYS_AGE'] / 365
# Mendapatkan nilai usia yang paling umum pada masing-masing FLAG
most_common_age_flag_0 = ages_flag_0.value_counts().idxmax()
most_common_age_flag_1 = ages_flag_1.value_counts().idxmax()
print("Usia peminjam yang paling sering dijumpai pada FLAG 0:", most_common_age_flag_0)
print("Usia peminjam yang paling sering dijumpai pada FLAG 1:", most_common_age_flag_1)
2.5 - Bagaimanakah hubungan antara Penghasilan dan Approved Credit berdasarkan Jumlah Anak¶
plt.figure(figsize=(10, 6))
sns.scatterplot(data=df_tr, x='INCOME', y='APPROVED_CREDIT', hue='NUM_OF_CHILDREN', palette='viridis', s=100)
plt.title('Hubungan antara INCOME dan APPROVED_CREDIT berdasarkan NUM_OF_CHILDREN')
plt.xlabel('INCOME')
plt.ylabel('APPROVED_CREDIT')
plt.legend(title='NUM_OF_CHILDREN')
plt.grid(True)
plt.show()
credit_by_child_max = df_tr.groupby('NUM_OF_CHILDREN')['APPROVED_CREDIT'].max()
credit_by_child_min = df_tr.groupby('NUM_OF_CHILDREN')['APPROVED_CREDIT'].min()
credit_by_child = pd.concat([credit_by_child_min, credit_by_child_max], axis=1)
credit_by_child.columns = ['APPROVED_CREDIT_MAX', 'APPROVED_CREDIT_MIN']
# Menemukan kisaran pendapatan tertinggi untuk persetujuan kredit
incomemin = df_tr.loc[df_tr['APPROVED_CREDIT'].idxmin(), 'INCOME']
incomemax = df_tr.loc[df_tr['APPROVED_CREDIT'].idxmax(), 'INCOME']
print("Persetujuan Kredit berdasarkan Jumlah Anak:")
print(credit_by_child)
print("\nKisaran Rentang Pendapatan Terendah-Tertinggi untuk Persetujuan Kredit:")
print(f"{incomemin} - {incomemax}")
Dapat dilihat jika jumlah kredit yang disetujui akan berbeda-beda tergantung jumlah anaknya. Terdapat penurunan yang lumayan signifikan ketika jumlah anak mulai dari 0-5 anak.
2.6 - Bagaimanakah distribusi dari masing-masing INCOME_CATEGORY terhadap APPROVED_CREDIT¶
df_tr['INCOME_CATEGORY'].value_counts()
Karena frekuensi untuk Unemployed, Businessman dan Student terlalu sedikit, maka tidak divisualisasi. Hal ini disebabkan karena plot distribusi tidak bisa terbentuk, mengingat plot distribusi terbentuk dari histogram berbasis frekuensi.
def draw_axvlines(plot, col):
df_summarywin = df_tr.describe()
mean = df_summarywin.loc["mean", col]
q1 = df_summarywin.loc["25%", col]
q2 = df_summarywin.loc["50%", col]
q3 = df_summarywin.loc["75%", col]
plot.axvline(mean, color="black", linestyle='dashed', label="Mean")
plot.axvline(q1, color="red", linestyle='dashed', label="25%")
plot.axvline(q2, color="blue", linestyle='dashed', label="50%")
plot.axvline(q3, color="purple", linestyle='dashed', label="75%")
plot.legend()
# Membuat subplots berdasarkan kategori INCOME_CATEGORY pada APPROVED_CREDIT
df_tr_filtered = df_tr[~df_tr['INCOME_CATEGORY'].isin(['Unemployed', 'Student', 'Businessman'])]
unique_income_categories = df_tr_filtered['INCOME_CATEGORY'].unique()
fig, axs = plt.subplots(len(unique_income_categories), 1, figsize=(10, 4*len(unique_income_categories)), sharex=True)
for idx, category in enumerate(unique_income_categories):
sns.histplot(data=df_tr_filtered[df_tr_filtered['INCOME_CATEGORY'] == category], x='APPROVED_CREDIT', kde=True, bins=30, color='skyblue', ax=axs[idx])
axs[idx].set_title(f'Distribusi APPROVED_CREDIT untuk INCOME_CATEGORY = {category}')
axs[idx].set_xlabel('APPROVED_CREDIT')
axs[idx].set_ylabel('Frekuensi')
draw_axvlines(axs[idx], 'APPROVED_CREDIT')
axs[idx].grid(True)
plt.tight_layout()
plt.show()
print("Rata-Rata Approved Credit berdasarkan Income Category")
df_winsorized.groupby("INCOME_CATEGORY")["APPROVED_CREDIT"].mean().reset_index()
2.7 Bagaimana rasio dan persebaran tipe pendidikan peminjam terhadap keterlambatan pembayaran yang berimplikasi pada tidak diberinya pinjaman?¶
education_delay_ratio = df_tr.groupby('EDUCATION')['FLAG'].mean()
plt.figure(figsize=(8, 6))
sns.barplot(x=education_delay_ratio.index, y=education_delay_ratio.values, palette='Set2')
plt.title('Pengaruh Pendidikan terhadap Tingkat Keterlambatan Pembayaran')
plt.xlabel('Tingkat Pendidikan')
plt.ylabel('Rasio Keterlambatan Pembayaran')
plt.xticks(rotation=60)
plt.show()
education_flag_counts = df_tr.groupby(['EDUCATION', 'FLAG']).size().unstack(fill_value=0)
education_flag_counts['Rasio Keterlambatan'] = education_flag_counts[1] / education_flag_counts.sum(axis=1)
education_flag_counts
2.8 Bagaimanakah distribusi dari APPLY_DAYS terhadap FLAG?¶
# Distribusi hari dalam seminggu (APPLY_DAYS) terhadap persetujuan pemberian pinjaman
sns.set(style="whitegrid")
# Membuat Countplot
plt.figure(figsize=(10, 6))
sns.countplot(data=df_tr, x='APPLY_DAYS', hue='FLAG', palette='Set2')
plt.title('Distribusi Hari Aplikasi Kredit dalam Seminggu Berdasarkan Persetujuan Kredit (FLAG)')
plt.xlabel('Hari dalam Seminggu')
plt.ylabel('Jumlah Aplikasi')
plt.xticks(rotation=45)
plt.legend(title='FLAG', labels=['FLAG = 0', 'FLAG = 1'])
plt.grid(True)
plt.show()
apply_days_flag_count = df_tr.groupby(['APPLY_DAYS', 'FLAG']).size().unstack(fill_value=0)
apply_days_flag_count['Rasio Pinjaman Ditolak'] = apply_days_flag_count[1] / apply_days_flag_count.sum(axis=1)
print("Tabel Jumlah Aplikasi Kredit Berdasarkan Hari dalam Seminggu dan Persetujuan Kredit (FLAG):")
print(apply_days_flag_count)
Dapat dilihat jika para peminjam di Hari Selasa biasanya memiliki rasio peminjaman ditolak tertinggi dibanding yang lainnya.
2.9 Bagaimanakah persebaran peminjam berdasarkan sumber penghasilan dan berasal dari kategori organisasi/instansi apa?¶
# Distribusi kategori pendapatan (INCOME_CATEGORY) terhadap persetujuan pemberian pinjaman
sns.set(style="whitegrid")
# Membuat Countplot
plt.figure(figsize=(10, 6))
sns.countplot(data=df_tr, x='INCOME_CATEGORY', hue='FLAG', palette='Set2')
plt.title('Distribusi Hari Aplikasi Kredit dalam Seminggu Berdasarkan Persetujuan Kredit (FLAG)')
plt.xlabel('Hari dalam Seminggu')
plt.ylabel('Jumlah Aplikasi')
plt.xticks(rotation=45)
plt.legend(title='FLAG', labels=['FLAG = 0', 'FLAG = 1'])
plt.grid(True)
plt.show()
inc_cat_flag_count = df_tr.groupby(['INCOME_CATEGORY', 'FLAG']).size().unstack(fill_value=0)
inc_cat_flag_count['Rasio Pinjaman Ditolak'] = inc_cat_flag_count[1] / inc_cat_flag_count.sum(axis=1)
print("Tabel Jumlah Aplikasi Kredit Berdasarkan Kategori Penghasilan dan Persetujuan Kredit (FLAG):")
print(inc_cat_flag_count)
Unemployed memiliki tingkat pinjaman ditolak tertinggi meskipun dengan jumlah observasi yang sedikit.
# Distribusi kategori organisasi (ORGANIZATION_CATEGORY) terhadap persetujuan pemberian pinjaman
sns.set(style="whitegrid")
# Membuat Countplot
plt.figure(figsize=(12, 6))
sns.countplot(data=df_tr, x='ORGANIZATION_CATEGORY', hue='FLAG', palette='Set2')
plt.title('Distribusi Hari Aplikasi Kredit dalam Seminggu Berdasarkan Persetujuan Kredit (FLAG)')
plt.xlabel('Hari dalam Seminggu')
plt.ylabel('Jumlah Aplikasi')
plt.xticks(rotation=90)
plt.legend(title='FLAG', labels=['FLAG = 0', 'FLAG = 1'])
plt.grid(True)
plt.show()
org_cat_flag_count = df_tr.groupby(['ORGANIZATION_CATEGORY', 'FLAG']).size().unstack(fill_value=0)
org_cat_flag_count['Rasio Pinjaman Ditolak'] = org_cat_flag_count[1] / org_cat_flag_count.sum(axis=1)
org_cat_flag_count_sorted = org_cat_flag_count.sort_values(by='Rasio Pinjaman Ditolak', ascending=False)
print("Tabel Jumlah Aplikasi Kredit Berdasarkan Kategori Organisasi terkait dan Persetujuan Kredit (FLAG):")
print(org_cat_flag_count_sorted)
3 - Preprocessing Data (2)¶
- Pada bagian ini dilakukan pra-pemrosesan data dan feature engineering melanjutkan proses data cleaning sebelumnya untuk digunakan dalam proses pemodelan berdasarkan insight yang diperoleh pada bagian EDA.
- Peserta diwajibkan membuat setidaknya 3 fitur baru, dengan mengekstrak nilai fitur dari dataset train.csv, test.csv, previous_application.csv dan payment_history.csv. Transformasi data dengan mengubah satuan (seperti hari menjadi tahun) tidak dihitung sebagai pembentukan fitur baru. Dataset utama dalam analisis ini adalah train.csv dan test.csv sehingga hasil fitur baru digabungkan dengan setiap dataset ini (tidak boleh salah satu).
3.1 Membuat Fitur PRE_LATE pada data test dan train secara bersamaan¶
import pandas as pd
# Membuat fitur PRE_LATE berdasarkan pembayaran yang terlambat
df_his['LATE'] = (df_his['PAY_DAYS'] < df_his['INST_DAYS']).astype(int)
# Mengagregasi informasi apakah ada keterlambatan untuk setiap U_ID
df_pre_late = df_his.groupby('U_ID')['LATE'].sum().reset_index()
df_pre_late['PRE-LATE'] = (df_pre_late['LATE'] > 0).astype(int)
df_pre_late.drop(columns='LATE', inplace=True)
# Gabungkan fitur PRE_LATE ke dataset train dan test
df_tr = df_tr.merge(df_pre_late, on='U_ID', how='left')
df_te = df_te.merge(df_pre_late, on='U_ID', how='left')
# Mengimputasi nilai NA pada fitur PRE_LATE dengan 0
df_tr['PRE-LATE'].fillna(0, inplace=True)
df_te['PRE-LATE'].fillna(0, inplace=True)
# Pastikan tipe data PRE_LATE adalah object
df_tr['PRE-LATE'] = df_tr['PRE-LATE'].astype(str)
df_te['PRE-LATE'] = df_te['PRE-LATE'].astype(str)
3.2 Membuat atribut baru berdasarkan anomalitas (keanehan) DAYS_WORK pada data test dan train secara bersamaan menjadi DAYS_WORK_ANOM¶
df_tr['DAYS_WORK'].value_counts()
Terdapat sebuah keanehan pada atribut ini. Days_Work menggambarkan berapa lama peminjam sudah bekerja sejak meminjam. Hal ini mengindikasikan adanya pengalaman bekerja dari para peminjam dalam hitungan hari. Setelah ditelusuri, angka negatif ini mengartikan bahwa pengambilan data dilakukan secara retrospektif atau melihat ke belakang. Oleh karena itu, melihat ke belakang sama saja mendapatkan nilai negatif berdasarkan selisih hari saat meminjam hingga pertama kali bekerja di masa lalu.
Terdapat keanehan pada nilai 365243 yang memiliki nilai positif dan sangat besar. Data ini mengalami sebuah kesalahan, oleh karena itu akan dibuat sebuah variabel baru yaitu anomalitas days_work. Sementara itu, kita akan mengganti nilai 365243 menjadi NaN dan akan dilakukan imputasi saat preprocessing (3)
# Membuat fitur DAYS_EMPLOYED_ANOM di df_tr dan df_te
df_tr['DAYS_EMPLOYED_ANOM'] = (df_tr["DAYS_WORK"] != 365243).astype(int)
df_te['DAYS_EMPLOYED_ANOM'] = (df_te["DAYS_WORK"] != 365243).astype(int)
# Mengganti nilai 365243 pada df_tr dan df_te menjadi NaN dan akan diimputasi di Preprocessing (3)
df_tr['DAYS_WORK'].replace({365243: np.nan}, inplace = True)
df_te['DAYS_WORK'].replace({365243: np.nan}, inplace = True)
3.3 Membuat fitur CREDIT_TERM pada data train dan test yang mengindikasikan jangka waktu dari pinjaman¶
# Membagi loan annuity dan approved credit menjadi credit term
df_tr['CREDIT_TERM'] = df_tr['LOAN_ANNUITY']/df_tr['APPROVED_CREDIT']
df_te['CREDIT_TERM'] = df_te['LOAN_ANNUITY']/df_te['APPROVED_CREDIT']
3.4 Membuat fitur HAS_LOAN_BEFORE berdasarkan Previous Applications¶
# Membuat fitur apakah pernah mengajukan pinjaman sebelumnya
df_tr['HAS_PREVIOUS_LOAN'] = df_tr['U_ID'].isin(df_pre['U_ID']).astype(object)
df_te['HAS_PREVIOUS_LOAN'] = df_te['U_ID'].isin(df_pre['U_ID']).astype(object)
Fitur ini menunjukkan apakah peminjam pernah melakukan peminjaman sebelumnya berdasarkan data Previous Applications
3.5 Membuat fitur DAYS_EMPLOYED_PERCENT¶
# Membagi lama bekerja dan usia menjadi persentase kepekerjaaan selama hidup
df_tr['DAYS_EMPLOYED_PERCENT'] = df_tr['DAYS_WORK'] / df_tr['DAYS_AGE']
df_te['DAYS_EMPLOYED_PERCENT'] = df_te['DAYS_WORK'] / df_te['DAYS_AGE']
Hal ini berarti persentase seseorang menghabiskan usianya untuk bekerja selama hidupnya. Bisa diartikan sebagai pengalaman bekerja juga
4 - Modelling¶
Hanya menggunakan dataset train.csv
Splitting Data¶
- Peserta bebas dalam pengaturan proporsi dan penggunaan random_state pada splitting data. Data latih (train) sekurang-kurangnya 60% dari train.csv
- Agar mempermudah analisis, train.csv dibagi menjadi 2 bagian, yaitu data train dan data validasi (bukan tes).
numerical_cols = [cname for cname in df_tr.columns if df_tr[cname].dtype in ['int64', 'float64']]
numerical_cols
cat_cols = [cname for cname in df_tr.columns if df_tr[cname].dtype in ['object']]
cat_cols
X = df_tr.drop(columns= 'FLAG')
y = df_tr['FLAG']
X_train, X_val, y_train, y_val = (train_test_split(X, y, test_size=0.2, stratify=y, random_state=42))
from sklearn.utils import resample
X = pd.concat([X_train, y_train], axis=1)
# Memisahkan income kurang dari 50 dan lebih dari 50
Flag0 = X[X.FLAG==0]
Flag1 = X[X.FLAG==1]
# upsample lebihdari50
income_upsampled = resample(Flag1,
replace=True, # sample with replacement
n_samples=len(Flag0), # match number in majority class
random_state=50) # reproducible results
# kombinasikan lebih dari 50 dan kurang dari 50
upsampled = pd.concat([Flag0, income_upsampled])
# mengecek value counts
upsampled.FLAG.value_counts()
Preprocessing Data (3) - Pipeline¶
- Beberapa tahapan preprocessing data menggunakan operator
pipelinepada scikit-learn agar lebih mudah digunakan dan menghindari kemungkinan terjadinya kebocoran (leakage) data tes saat pemodelan. - Peserta diwajibkan menggunakan setidaknya 3 metode preprocessing data berbeda pada tahapan preprocessing bagian 3 (
pipeline). Jika dilakukan imputasi missing value menggunakan modus untuk data kategorik dan mean untuk data numerik akan dihitung sebagai 1 metode preprocessing yang sama.
# Melihat tipe data pada X train
X_train.info()
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OrdinalEncoder
# Mendefinisikan kolom numerik dan kategorikal
numeric_cols = ['NUM_OF_CHILDREN', 'INCOME', 'PRODUCT_PRICE', 'DAYS_AGE', 'DAYS_WORK', 'EXTERNAL_SCORE_1', 'EXTERNAL_SCORE_2', 'EXTERNAL_SCORE_3', 'DAYS_SINCE_ID_CHANGE', 'CREDIT_TERM', 'DAYS_EMPLOYED_PERCENT', 'DAYS_REGISTRATION']
categorical_cols = ['INCOME_CATEGORY', 'DAYS_EMPLOYED_ANOM', 'ORGANIZATION_CATEGORY', 'HAS_PREVIOUS_LOAN']
# Membangun pipeline untuk kolom numerik
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())])
# Membangun pipeline untuk kolom kategorikal
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OrdinalEncoder())])
# Menggabungkan transformer untuk kolom numerik dan kategorikal
preprocessor = ColumnTransformer(
transformers=[
('num', numeric_transformer, numeric_cols),
('cat', categorical_transformer, categorical_cols)])
Pemodelan¶
- Pilihlah metrik evaluasi yang Anda gunakan untuk menilai performa model (tahapan pemodelan serta pemilihan model terbaik) dan berikan penjelasan menyeluruh tentang alasan Anda memilih metrik tersebut.
- Pilihlah model terbaik dengan membandingkan beberapa model klasifikasi (minimal 7 model yang berbeda) dan berikan penjelasan mengapa model tersebut dipilih sebagai yang terbaik.
Metrik evaluasi yang digunakan: F1-Score
karena seperti yang kita ketahui data kita beberapa ada yang tidak seimbang seperti pada flag, setelah dilakukan oversampling maka alangkah baiknya tetap menggunakan F1-Score. F1-score adalah harmonic mean dari presisi dan recall. Metrik ini memberikan keseimbangan antara presisi dan recall, dan berguna ketika kita ingin memperhatikan keduanya secara seimbang. Selain itu, menurut saya metrik ini juga sudah lumayan bisa merepresentasikan presisi dan recall dari model. F1-Score juga bagus digunakan saat distribusi kelas tidak seimbang.
# Membuat metrik evaluasi beserta nilai-nilai dari metrik evaluasinya tidak lupa dengan classification report
from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score, classification_report
def evaluate_classification(y_true, y_pred):
accuracy = accuracy_score(y_true, y_pred)
precision = precision_score(y_true, y_pred)
recall = recall_score(y_true, y_pred)
f1 = f1_score(y_true, y_pred)
print(classification_report(y_true, y_pred))
return {'Accuracy': accuracy, 'Precision': precision, 'Recall': recall, 'F1-score': f1}
1 - Random Forest¶
# Menggabungkan preprocessor dengan model
pipeline = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', RandomForestClassifier())])
# Melatih model
model1 = pipeline.fit(X_train, y_train)
# Membuat prediksi
Yrf_pred = pipeline.predict(X_val)
# Cek laporan klasifikasi
evaluate_classification(y_val, Yrf_pred)
2 - K-Nearest Neighbors (KNN)¶
from sklearn.neighbors import KNeighborsClassifier
# Menggabungkan preprocessor dengan model
pipeline = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', KNeighborsClassifier())])
# Melatih model
model2 = pipeline.fit(X_train, y_train)
# Membuat prediksi
Yknn_pred = pipeline.predict(X_val)
# Cek laporan klasifikasi
evaluate_classification(y_val, Yknn_pred)
3 - Decision Trees¶
from sklearn.tree import DecisionTreeClassifier
# Inisialisasi model
pipeline = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', DecisionTreeClassifier())])
# Latih model
model3 = pipeline.fit(X_train, y_train)
# Membuat prediksi
Ydectree_pred = pipeline.predict(X_val)
# Cek laporan klasifikasi
evaluate_classification(y_val, Ydectree_pred)
4 - Support Vector Machine (SVM)¶
from sklearn.svm import SVC
# Inisialisasi model
pipeline = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', SVC())])
# Latih model
model4 = pipeline.fit(X_train, y_train)
# Membuat prediksi
Ysvm_pred = pipeline.predict(X_val)
# Cek laporan klasifikasi
evaluate_classification(y_val, Ysvm_pred)
5 - Logistic Regression¶
from sklearn.linear_model import LogisticRegression
# Inisialisasi model
pipeline = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', LogisticRegression())])
# Latih model
model5 = pipeline.fit(X_train, y_train)
# Membuat prediksi
Ylog_pred = pipeline.predict(X_val)
# Cek laporan klasifikasi
evaluate_classification(y_val, Ylog_pred)
6 - Naive Bayes¶
from sklearn.naive_bayes import GaussianNB
# Inisialisasi model
pipeline = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', GaussianNB())])
# Latih model
model6 = pipeline.fit(X_train, y_train)
# Membuat prediksi
Ynb_pred = pipeline.predict(X_val)
# Cek laporan klasifikasi
evaluate_classification(y_val, Ynb_pred)
7 - Gradient Boosting Machines (GBM)¶
from sklearn.ensemble import GradientBoostingClassifier
# Inisialisasi model
pipeline = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', GradientBoostingClassifier())])
# Latih model
model7 = pipeline.fit(X_train, y_train)
# Membuat prediksi
Ygbm_pred = pipeline.predict(X_val)
# Cek laporan klasifikasi
evaluate_classification(y_val, Ygbm_pred)
8 - Multilayer Perceptron (MLP)¶
from sklearn.neural_network import MLPClassifier
# Inisialisasi model
pipeline = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', MLPClassifier())])
# Latih model
model8 = pipeline.fit(X_train, y_train)
# Membuat prediksi
Ymlp_pred = pipeline.predict(X_val)
# Cek laporan klasifikasi
evaluate_classification(y_val, Ymlp_pred)
9 - Extreme Gradient Boosting (XGBoost):¶
from xgboost import XGBClassifier
# Inisialisasi model
pipeline = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', XGBClassifier())])
# Latih model
model9 = pipeline.fit(X_train, y_train)
# Membuat prediksi
Yxgb_pred = pipeline.predict(X_val)
# Cek laporan klasifikasi
evaluate_classification(y_val, Yxgb_pred)
10 - Ada Boost¶
from sklearn.ensemble import AdaBoostClassifier
# Inisialisasi model
pipeline = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', AdaBoostClassifier())])
# Latih model
model10 = pipeline.fit(X_train, y_train)
# Membuat prediksi
Yada_pred = pipeline.predict(X_val)
# Cek laporan klasifikasi
evaluate_classification(y_val, Yada_pred)
11 - Quadratic Discriminant Analysis (QDA)¶
from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis
# Inisialisasi model
pipeline = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', QuadraticDiscriminantAnalysis())])
# Latih model
model11 = pipeline.fit(X_train, y_train)
# Membuat prediksi
Yqda_pred = pipeline.predict(X_val)
# Cek laporan klasifikasi
evaluate_classification(y_val, Yqda_pred)
Kumpulan semua model¶
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score
from sklearn.model_selection import KFold
import pandas as pd
def evaluate_models(X_train, y_train, X_val, y_val, models):
results = {}
for model_name, model in models.items():
pipeline = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', model)])
# Melatih model menggunakan data pelatihan
pipeline.fit(X_train, y_train)
# Melakukan prediksi pada data uji
y_pred = pipeline.predict(X_val)
# Menghitung performa model
accuracy = accuracy_score(y_val, y_pred)
precision = precision_score(y_val, y_pred)
recall = recall_score(y_val, y_pred)
f1 = f1_score(y_val, y_pred)
roc_auc = roc_auc_score(y_val, y_pred)
# Menyimpan hasil performa model
results[model_name] = {'Accuracy': accuracy,
'Precision': precision,
'Recall': recall,
'F1 Score': f1,
'ROC AUC Score': roc_auc}
return pd.DataFrame(results).T
# Menyusun kandidat model
models = {
'Random Forest': RandomForestClassifier(),
'K Neighbors': KNeighborsClassifier(),
'Decision Tree': DecisionTreeClassifier(),
'SVM': SVC(),
'Logistic Regression': LogisticRegression(),
'Gaussian Naive Bayes': GaussianNB(),
'Gradient Boosting': GradientBoostingClassifier(),
'MLP': MLPClassifier(),
'XGBoost': XGBClassifier(),
'AdaBoost': AdaBoostClassifier(),
'Quadratic Discriminant Analysis': QuadraticDiscriminantAnalysis()
}
# Memanggil fungsi untuk mengevaluasi model
evaluation_results = evaluate_models(X_train, y_train, X_val, y_val, models)
# Menampilkan hasil evaluasi dalam bentuk tabel
print(evaluation_results)
Model Terbaik¶
best = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', GaussianNB())]) # model terbaik
best.fit(X_train, y_train) # fitting model terbaik menggunakan data latih
5 - Evaluation¶
Lakukanlah uji performa model terbaik di atas dengan memprediksi data test.csv menggunakan setidaknya 3 metrik evaluasi yang berbeda dan berikan interpretasi.
X_test = df_te.drop(columns= 'FLAG')
y_test = df_te['FLAG']
# Predict the test set
Y_pred = best.predict(X_test)
# Check the classification report
print(classification_report(y_test, Y_pred))
accuracy = accuracy_score(y_test, Y_pred)
precision = precision_score(y_test, Y_pred)
recall = recall_score(y_test, Y_pred)
f1 = f1_score(y_test, Y_pred)
roc_auc = roc_auc_score(y_test, Y_pred)
conf_matrix = confusion_matrix(y_test, Y_pred)
# Menampilkan hasil evaluasi
print("Accuracy:", accuracy)
print("Precision:", precision)
print("Recall:", recall)
print("F1 Score:", f1)
print("ROC-AUC Score:", roc_auc)
# Menampilkan confusion matrix
print("Confusion Matrix:")
print(conf_matrix)
Interpretasi Terlihat jika nilai F1-Score naik dari awalnya 0.236959 menjadi 0.24692179700499167. Selain itu, terjadi kenaikan pada metrik evaluasi selain F1 Score. Jika F1-score naik diiringi kenaikan precision dan recall maka dapat diindikasikan jika data bisa dikatakan balance. Seperti yang kita ketahui F1 score adalah harmonic mean dari presisi dan recall. Hal ini karena sudah dilakukan balancing menggunakan oversampling di atas. ROC AUC juga mengalami kenaikan memiliki makna bahwa model sudah bisa mengukur seberapa baik model membedakan antara dua kelas. ROC AUC juga erguna saat kita memiliki masalah klasifikasi dengan distribusi kelas yang tidak seimbang dan ketika kita ingin mempertimbangkan semua tingkat ambang secara keseluruhan.
6 - Post Analysis¶
- Berikan penjelasan tentang fitur-fitur yang paling penting pada model terbaik yang dipilih dan jelaskan bagaimana dan mengapa fitur-fitur tersebut sangat penting serta bagaimana pola pengaruhnya terhadap label target (
FLAG) - Jalankan syntax berikut tanpa mengubah apapun. Tugas anda adalah memberikan interpretasi pada masing-masing output
Feature Importance¶
from sklearn.inspection import permutation_importance
import shap
def plot_fi(model, X = X_val, y = y_val, rep = 10):
perm = permutation_importance(model, X, y, n_repeats=10, random_state=0, n_jobs=-1)
perm2 = pd.DataFrame({'feature': X.columns.tolist()*rep, 'importance': perm["importances"].transpose().reshape(-1)})
perm2["importance"] = perm2.importance/perm2.importance.sum()*rep
urut = perm2.groupby("feature").mean().sort_values("importance", ascending=False)
plt.figure(figsize=(8, 6))
fig, axs = plt.subplots(1, 2, figsize=(25, 15))
sns.barplot(x='importance', y='feature', data=perm2, order=urut.index, ax=axs[0])
sns.stripplot(x='importance', y='feature', data=perm2, order = urut.index, s=5, ax=axs[1])
plt.show()
return urut
plot_fi(model = best, X = X_val, y = y_val)
DAYS_AGE Usia seseorang dapat menjadi indikasi stabilitas keuangan dan kemampuan untuk membayar pinjaman. Umumnya, semakin tua usia seseorang, semakin stabil keuangannya, yang dapat mengurangi risiko gagal bayar.
DAYS_EMPLOYED_ANOMpenting karena lamanya seseorang bekerja dapat mempengaruhi kemampuan mereka untuk membayar pinjaman. Anomali dalam lamanya bekerja mungkin menunjukkan informasi yang tidak konsisten atau tidak dapat dipercaya, yang dapat mempengaruhi keputusan pemberian pinjaman.
DAYS_WORK Seseorang yang telah bekerja untuk waktu yang lama mungkin memiliki stabilitas keuangan yang lebih besar dan kemampuan untuk membayar kembali pinjaman.
PRODUCT_PRICE penting karena jumlah pinjaman yang diminta dapat mempengaruhi kemampuan peminjam untuk membayar kembali pinjaman. Jumlah pinjaman yang lebih tinggi dapat mengindikasikan risiko yang lebih tinggi bagi pemberi pinjaman.
DAYS_EMPLOYED_PERCENT Penting karena fitur ini dapat memberikan informasi tentang stabilitas karier dan keuangan peminjam.
HAS_PREVIOUS_LOAN Penting karena dapat menunjukkan apakah peminjam memiliki pinjaman sebelumnya. Ini bisa menjadi indikasi pengalaman peminjam dengan pinjaman sebelumnya dan kemungkinan membayar kembali pinjaman saat ini.
Opsional -- SHAP values¶
Opsional -- SHAP values individual / SHAP Force Plot¶
7 - Conclusion & Recommendation¶
Berikan rekomendasi & kesimpulan menyeluruh terhadap bisnis PDM Paylater berdasarkan hasil analisis yang telah dilakukan.
KESIMPULAN: Kesimpulan yang dapat diperoleh adalah model Gaussian Naive Bayes adalah model terbaik yang bisa mengklasifikasikan para peminjam di PDM Paylater berdasarkan kriteria-kriteria peminjam dengan keberhasilan diberikan pinjaman. Telah dilakukan rangkaian operasi mulai dari Preprocessing, Preprocessing dengan Pipeline, hingga Modelling serta Uji Performa Model. Selanjutnya, juga sudah digambarkan seberapa penting atribut-atribut yang ada di dalam data terhadap keberhasilan pemberian pinjaman. Hal ini tergambar melalui tabel feature importance.
REKOMENDASI: Berdasarkan apa yang sudah dianalisis karena kegagalan pembayaran memiliki risiko yang tinggi terhadap kriteria peminjam PDM Paylater memang harus lumayan selektif dalam memilih atribut-atribut untuk para peminjam. Hal ini bisa dilihat dari feature importance yang menandakan seberapa berpengaruh atribut tersebut terhadap pemberian pinjaman. Selain itu, pengumpulan data eksternal dan juga kesalahan data harus terus diperhatikan agar tidak terjadi kesalahan.